﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Singer.Core
{
    public class JsonUtils
    {
        public class JsonPropertyContractResolver : CamelCasePropertyNamesContractResolver
        {
            private IEnumerable<string> lstInclude;

            private IEnumerable<string> lstIgnore;

            public JsonPropertyContractResolver()
            {
            }

            public JsonPropertyContractResolver(IEnumerable<string> includeProperties, IEnumerable<string> ignoreProperties)
            {
                lstInclude = includeProperties;
                lstIgnore = ignoreProperties;
            }

            protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
            {
                IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
                if (lstInclude != null)
                {
                    return list.Where((JsonProperty p) => lstInclude.Contains<string>(p.PropertyName)).ToList();
                }

                if (lstIgnore != null)
                {
                    return list.Where((JsonProperty p) => !lstIgnore.Contains<string>(p.PropertyName)).ToList();
                }

                return list;
            }
        }

        public static T ConvertTo<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }

        public static T ToModel<T>(string json)
        {
            return ConvertTo<T>(json);
        }

        public static T ToModel<T>(object model)
        {
            return ConvertTo<T>(ToJson(model));
        }

        public static object ToModel(string json, Type type)
        {
            return JsonConvert.DeserializeObject(json, type);
        }

        public static JToken ConvertToObject(string json)
        {
            return JToken.Parse(json);
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="indented">是否保留格式，不压缩</param>
        public static string ToJson(object obj, bool indented = false)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss",
                ContractResolver = new JsonPropertyContractResolver(),
                NullValueHandling = NullValueHandling.Include
            };
            return JsonConvert.SerializeObject(obj, indented ? Formatting.Indented : Formatting.None, settings);
        }

        public static string ToJson(object obj, JsonSerializerSettings setting)
        {
            return JsonConvert.SerializeObject(obj, setting);
        }

        public static string ToJson(object obj, bool indented, IEnumerable<string> ignores)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss",
                ContractResolver = new JsonPropertyContractResolver(null, ignores),
                NullValueHandling = NullValueHandling.Include
            };
            return JsonConvert.SerializeObject(obj, indented ? Formatting.Indented : Formatting.None, settings);
        }

        /// <summary>
        /// 递归查找子节点的值
        /// </summary>
        public static List<JToken> FindTokens(JToken containerToken, string name)
        {
            List<JToken> list = new List<JToken>();
            try
            {
                FindTokens(containerToken, name, list);
                return list;
            }
            catch (Exception)
            {
                return list;
            }
        }

        private static void FindTokens(JToken containerToken, string name, List<JToken> matches)
        {
            if (containerToken.Type == JTokenType.Object)
            {
                foreach (JProperty item in containerToken.Children<JProperty>())
                {
                    if (item.Name == name)
                    {
                        matches.Add(item.Value);
                    }

                    FindTokens(item.Value, name, matches);
                }
            }
            else
            {
                if (containerToken.Type != JTokenType.Array)
                {
                    return;
                }

                foreach (JToken item2 in containerToken.Children())
                {
                    FindTokens(item2, name, matches);
                }
            }
        }
    }
}
